<template>
  <div class="page">
    <a-breadcrumb style="margin-bottom:12px">
      <a-breadcrumb-item><router-link to="/">首页</router-link></a-breadcrumb-item>
      <a-breadcrumb-item>{{ detail?.title || '文章详情' }}</a-breadcrumb-item>
    </a-breadcrumb>

    <a-card :loading="loading">
      <template #title>
        <div class="title">{{ detail?.title }}</div>
      </template>
      <template #extra>
        <a-button type="primary" shape="round" :disabled="liked || !detail" @click="onLike">
          {{ liked ? '已点赞' : '点赞' }}（{{ detail?.likeCount ?? 0 }}）
        </a-button>
      </template>
      <div class="meta">
        <span class="link" v-if="detail?.categoryId" @click="$router.push({ name: 'CategoryPage', params: { id: detail?.categoryId } })">{{ detail?.categoryName || '未分类' }}</span>
        <span v-else>{{ detail?.categoryName || '未分类' }}</span>
        <span>{{ detail?.authorName || '匿名' }}</span>
        <span>{{ formatDate(detail?.createTime) }}</span>
      </div>
      <div v-if="detail?.coverImage" class="cover">
        <a-image :src="detail?.coverImage" :preview="false" />
      </div>
      <div class="content" v-html="html"></div>

      <a-divider />
      <div class="related">
        <div class="related-title">相关文章</div>
        <a-list :grid="{ gutter: 16, xs: 1, sm: 2, md: 2, lg: 3 }" :data-source="related" :locale="{ emptyText: '暂无推荐' }">
          <template #renderItem="{ item }">
            <a-list-item>
              <a-card :hoverable="true" class="related-card" @click="$router.push({ name: 'ArticleDetail', params: { id: item.id } })">
                <template v-if="item.coverImage" #cover>
                  <a-image :src="item.coverImage" :preview="false" />
                </template>
                <a-card-meta :title="item.title">
                  <template #description>
                    <div class="related-summary">{{ item.summary }}</div>
                    <div class="related-stats">
                      <span>👁️ {{ item.viewCount }}</span>
                      <span>👍 {{ item.likeCount }}</span>
                      <span>💬 {{ item.commentCount }}</span>
                    </div>
                  </template>
                </a-card-meta>
              </a-card>
            </a-list-item>
          </template>
        </a-list>
      </div>

      <a-divider />
      <div class="comments">
        <div class="comments-title">评论</div>
        <a-form layout="vertical" @submit.prevent>
          <a-form-item label="昵称">
            <a-input v-model:value="form.nickname" placeholder="可选" />
          </a-form-item>
          <a-form-item label="邮箱">
            <a-input v-model:value="form.email" placeholder="可选" type="email" />
          </a-form-item>
          <a-form-item label="内容" required>
            <a-textarea v-model:value="form.content" :rows="4" placeholder="说点什么吧..." />
          </a-form-item>
          <a-form-item label="图片">
            <SmartUpload file-type="image" :multiple="true" :max-count="6" @uploaded="(url:string)=> appendImageUrl(url)" />
          </a-form-item>
          <a-form-item label="验证码" required>
            <a-space>
              <a-input v-model:value="form.captchaAnswer" placeholder="请输入答案" style="width: 160px" />
              <a-tag color="blue" @click="reloadCaptcha" style="cursor: pointer">{{ captcha?.question || '点击获取验证码' }}</a-tag>
            </a-space>
          </a-form-item>
          <a-space>
            <a-button type="primary" :loading="submitting" @click="onSubmitComment">发表评论</a-button>
            <a-button @click="onReset">重置</a-button>
          </a-space>
        </a-form>

        <a-list
          class="comment-list"
          :data-source="commentTrees"
          :locale="{ emptyText: '暂无评论' }"
          style="margin-top: 16px"
        >
          <template #renderItem="{ item }">
            <a-list-item>
              <a-comment :author="item.nickname || '匿名'">
                <template #avatar>
                  <a-avatar shape="circle">{{ (item.nickname || '匿').charAt(0) }}</a-avatar>
                </template>
                <template #content>
                  <div class="comment-content">{{ item.content }}</div>
                  <div class="comment-actions">
                    <a @click="toggleReply(item.id)">回复</a>
                    <a-divider type="vertical" />
                    <a @click="toggleLike(item.id)">{{ likedCommentIds.has(item.id) ? '已赞' : '点赞' }} {{ commentLikeCountMap[item.id] || 0 }}</a>
                    <a-divider type="vertical" />
                    <a @click="toggleChildren(item.id)">{{ collapsedSet.has(item.id) ? '展开' : '折叠' }}回复</a>
                  </div>
                  <div v-if="replyingParentId === item.id" class="reply-box">
                    <a-textarea v-model:value="replyContentMap[item.id]" :rows="3" placeholder="回复内容..." />
                    <a-space style="margin-top:8px">
                      <a-button type="primary" size="small" :loading="replySubmitting" @click="onSubmitReply(item.id)">提交</a-button>
                      <a-button size="small" @click="cancelReply">取消</a-button>
                    </a-space>
                  </div>
                </template>
                <template #datetime>
                  <a-tooltip :title="formatDate(item.createTime)">
                    <span>{{ fromNow(item.createTime) }}</span>
                  </a-tooltip>
                </template>

                <template #default>
                  <template v-if="!collapsedSet.has(item.id)">
                  <a-comment v-for="child in item.children" :key="child.id" :author="child.nickname || '匿名'">
                    <template #avatar>
                      <a-avatar shape="circle">{{ (child.nickname || '匿').charAt(0) }}</a-avatar>
                    </template>
                    <template #content>
                      <div class="comment-content">{{ child.content }}</div>
                      <div class="comment-actions small">
                        <a @click="toggleLike(child.id)">{{ likedCommentIds.has(child.id) ? '已赞' : '点赞' }} {{ commentLikeCountMap[child.id] || 0 }}</a>
                      </div>
                    </template>
                    <template #datetime>
                      <a-tooltip :title="formatDate(child.createTime)">
                        <span>{{ fromNow(child.createTime) }}</span>
                      </a-tooltip>
                    </template>
                  </a-comment>
                  </template>
                </template>
              </a-comment>
            </a-list-item>
          </template>
        </a-list>

        <div class="pager" v-if="commentTotal > commentPageSize">
          <a-pagination
            :current="commentPageNo"
            :page-size="commentPageSize"
            :total="commentTotal"
            @change="onCommentPageChange"
          />
        </div>
      </div>
    </a-card>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, computed, reactive, watch } from 'vue'
import { useRoute } from 'vue-router'
import { fetchArticleDetail, likeArticle, fetchComments, addComment, fetchRelatedArticles, likeComment, fetchCommentLikes } from '@/api/public/articles'
import { fetchQACaptcha } from '@/api/captcha'
import type { ArticleDetailVO, CommentVO, CreateCommentDTO, CommentTreeVO, PageResponse, ArticleListItemVO } from '@/types/api'
import { marked } from 'marked'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import 'dayjs/locale/zh-cn'
import { message } from 'ant-design-vue'
import { useHead } from '@vueuse/head'
import SmartUpload from '@/components/SmartUpload.vue'

const route = useRoute()
const loading = ref(false)
const detail = ref<ArticleDetailVO | null>(null)
const liked = ref(false)
const comments = ref<CommentVO[]>([])
const commentTrees = ref<CommentTreeVO[]>([])
const submitting = ref(false)
const form = ref<CreateCommentDTO>({ content: '' })
const imageUrls = ref<string[]>([])
const captcha = ref<{ token: string; question: string; ttl: number } | null>(null)
const commentPageNo = ref(1)
const commentPageSize = ref(10)
const commentTotal = ref(0)
const replyingParentId = ref<number | null>(null)
const replyContentMap = reactive<Record<number, string>>({})
const replySubmitting = ref(false)
const related = ref<ArticleListItemVO[]>([])
const likedCommentIds = reactive(new Set<number>())
const commentLikeCountMap = reactive<Record<number, number>>({})
const collapsedSet = reactive(new Set<number>())

const html = computed(() => detail.value?.content ? marked.parse(detail.value.content) : '')

function formatDate(s?: string) {
  if (!s) return ''
  return dayjs(s).format('YYYY-MM-DD HH:mm:ss')
}

dayjs.extend(relativeTime)
dayjs.locale('zh-cn')
function fromNow(s?: string) {
  if (!s) return ''
  return dayjs(s).fromNow()
}

async function load() {
  const id = Number(route.params.id)
  if (!id) return
  loading.value = true
  try {
    const { data } = await fetchArticleDetail(id)
    detail.value = data
    useHead({
      title: `${data.title} - 个人博客` ,
      meta: [
        { name: 'description', content: data.summary || data.title },
        { name: 'keywords', content: (data.tags || '').replace(/,/g, ', ') },
        // Open Graph
        { property: 'og:title', content: data.title },
        { property: 'og:description', content: data.summary || data.title },
        { property: 'og:type', content: 'article' },
        { property: 'og:url', content: `${window.location.origin}/article/${data.id}` },
        ...(data.coverImage ? [{ property: 'og:image', content: data.coverImage }] : []),
        // Twitter Card
        { name: 'twitter:card', content: data.coverImage ? 'summary_large_image' : 'summary' },
        { name: 'twitter:title', content: data.title },
        { name: 'twitter:description', content: data.summary || data.title },
        ...(data.coverImage ? [{ name: 'twitter:image', content: data.coverImage }] : [])
      ],
      script: [
        {
          type: 'application/ld+json',
          children: JSON.stringify({
            '@context': 'https://schema.org',
            '@type': 'BlogPosting',
            headline: data.title,
            datePublished: data.createTime,
            dateModified: data.updateTime || data.createTime,
            description: data.summary || data.title,
            image: data.coverImage ? [data.coverImage] : undefined,
            mainEntityOfPage: {
              '@type': 'WebPage',
              '@id': `${window.location.origin}/article/${data.id}`
            }
          })
        }
      ]
    })
    liked.value = localStorage.getItem(`liked_article_${id}`) === '1'
    // 相关文章
    const rel = await fetchRelatedArticles(id, 6)
    related.value = rel.data || []
    const c = await fetchComments(id, true, commentPageNo.value, commentPageSize.value)
    const payload = c.data as PageResponse<CommentTreeVO>
    commentTrees.value = payload.records || []
    commentTotal.value = payload.total || 0
    // 拉取当前页顶层评论的点赞数
    const allIds: number[] = []
    for (const t of commentTrees.value || []) {
      allIds.push(t.id)
      for (const c of t.children || []) allIds.push(c.id)
    }
    if (allIds.length) {
      const resp = await fetchCommentLikes(allIds)
      const map = resp.data || {}
      Object.keys(map).forEach(k => {
        const idNum = Number(k)
        commentLikeCountMap[idNum] = map[idNum] || 0
      })
    }
  } finally {
    loading.value = false
  }
}

async function onLike() {
  if (!detail.value || liked.value) return
  const id = Number(route.params.id)
  try {
    await likeArticle(id)
    detail.value.likeCount = (detail.value.likeCount || 0) + 1
    liked.value = true
    localStorage.setItem(`liked_article_${id}`, '1')
  } catch (e) {
    // ignore
  }
}

async function onSubmitComment() {
  const id = Number(route.params.id)
  if (!id) return
  if (!form.value.content || form.value.content.trim().length === 0) {
    message.warning('请输入评论内容')
    return
  }
  if (!captcha.value?.token || !form.value.captchaAnswer) {
    message.warning('请先获取并填写验证码')
    return
  }
  submitting.value = true
  try {
    const contentWithImages = form.value.content + (imageUrls.value.length ? ('\n' + imageUrls.value.map(u => `![image](${u})`).join('\n')) : '')
    await addComment(id, { ...form.value, content: contentWithImages, captchaToken: captcha.value.token })
    message.success('评论已提交')
    form.value = { content: '' }
    captcha.value = null
    const c = await fetchComments(id, true, commentPageNo.value, commentPageSize.value)
    const payload = c.data as PageResponse<CommentTreeVO>
    commentTrees.value = payload.records || []
    commentTotal.value = payload.total || 0
    if (detail.value) {
      detail.value.commentCount = (detail.value.commentCount || 0) + 1
    }
  } finally {
    submitting.value = false
  }
}
function appendImageUrl(url: string) {
  imageUrls.value.push(url)
}

function onReset() {
  form.value = { content: '' }
  captcha.value = null
}

onMounted(load)

onMounted(() => {
  reloadCaptcha()
})

watch(() => route.params.id, () => {
  commentPageNo.value = 1
  commentTotal.value = 0
  replyingParentId.value = null
  Object.keys(replyContentMap).forEach(k => delete replyContentMap[Number(k)])
  load()
  try { window.scrollTo({ top: 0, behavior: 'smooth' }) } catch { /* ignore */ }
})

function onCommentPageChange(p: number) {
  commentPageNo.value = p
  load()
}

async function reloadCaptcha() {
  try {
    captcha.value = await fetchQACaptcha()
  } catch (e) {
    captcha.value = null
  }
}

function toggleReply(parentId: number) {
  replyingParentId.value = replyingParentId.value === parentId ? null : parentId
  if (replyingParentId.value === parentId) {
    replyContentMap[parentId] = replyContentMap[parentId] || ''
  }
}

function cancelReply() {
  replyingParentId.value = null
}

async function onSubmitReply(parentId: number) {
  const id = Number(route.params.id)
  if (!id) return
  const content = (replyContentMap[parentId] || '').trim()
  if (!content) {
    message.warning('请输入回复内容')
    return
  }
  if (!captcha.value?.token || !form.value.captchaAnswer) {
    message.warning('请先获取并填写验证码')
    return
  }
  replySubmitting.value = true
  try {
    await addComment(id, { content, parentId, captchaToken: captcha.value.token, captchaAnswer: form.value.captchaAnswer })
    message.success('回复已提交')
    replyingParentId.value = null
    delete replyContentMap[parentId]
    captcha.value = null
    const c = await fetchComments(id, true, commentPageNo.value, commentPageSize.value)
    const payload = c.data as PageResponse<CommentTreeVO>
    commentTrees.value = payload.records || []
    commentTotal.value = payload.total || 0
    if (detail.value) {
      detail.value.commentCount = (detail.value.commentCount || 0) + 1
    }
  } finally {
    replySubmitting.value = false
  }
}

function toggleLike(id: number) {
  const key = `liked_comment_${id}`
  if (likedCommentIds.has(id) || localStorage.getItem(key) === '1') return
  likedCommentIds.add(id)
  commentLikeCountMap[id] = (commentLikeCountMap[id] || 0) + 1
  localStorage.setItem(key, '1')
  // 同步到后端计数（忽略失败）
  likeComment(id).catch(() => {})
}

function toggleChildren(id: number) {
  if (collapsedSet.has(id)) collapsedSet.delete(id)
  else collapsedSet.add(id)
}
</script>

<style scoped>
.page {
  max-width: 960px;
  margin: 0 auto;
  padding: 12px;
}
.title {
  font-size: 22px;
  font-weight: 600;
}
.meta {
  margin-bottom: 12px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  color: rgba(0,0,0,0.45);
}
.cover { margin: 12px 0; }
.content :deep(img) { max-width: 100%; }
.ant-card-extra { display: flex; align-items: center; }
.comments { margin-top: 16px; }
.comments-title { font-weight: 600; margin-bottom: 8px; }
.comment-list :deep(.ant-comment) { padding: 8px 0; }
.comment-list :deep(.ant-comment-content-author) { margin-bottom: 4px; }
.comment-list :deep(.ant-avatar) { background: #1890ff; color: #fff; }
.comment-list :deep(.ant-comment-content-detail) { white-space: pre-wrap; }
.related { margin-top: 16px; }
.related-title { font-weight: 600; margin-bottom: 8px; }
.related-card { height: 100%; }
.related-summary { color: rgba(0,0,0,0.65); margin-top: 6px; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.related-stats { margin-top: 6px; display: flex; gap: 10px; color: rgba(0,0,0,0.45); font-size: 12px; }
.comment-actions.small { margin-top: 4px; font-size: 12px; color: rgba(0,0,0,0.45); }
</style>


